package com.srlg.app.controller;

import com.srlg.app.model.dto.UploadFileParamsDto;
import com.srlg.app.model.po.MediaFiles;
import com.srlg.app.service.MediaFilesService;
import com.srlg.common.req.R;
import io.swagger.v3.oas.annotations.ExternalDocumentation;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.media.Content;
import io.swagger.v3.oas.annotations.media.Schema;
import io.swagger.v3.oas.annotations.responses.ApiResponse;
import io.swagger.v3.oas.annotations.tags.Tag;
import lombok.RequiredArgsConstructor;
import org.springframework.http.MediaType;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;

import java.io.File;
import java.util.List;

@RestController
@RequiredArgsConstructor
@Tag(
    name = "MinioControllerAPI",
    description = "minio控制器接口",
    externalDocs = @ExternalDocumentation(
        description = "这是一个接口文档介绍",
        url = "https://www.srlg.com/"))
public class MinioController {

    private final MediaFilesService mediaFilesService;

    /**
     * 获取全部文件
     */
    @Operation(
        summary = "查询全部文件",
        description = "查询全部文件信息，并返回响应结果信息",
        parameters = {},
        deprecated = false,
        responses = {
            @ApiResponse(
                responseCode = "200",
                description = "响应成功",
                content = @Content(
                    mediaType = MediaType.APPLICATION_JSON_VALUE,
                    schema = @Schema(
                        title = "R和List<MediaFiles>组合模型",
                        description = "返回实体，AjaxResult内data为" +
                            "MediaFiles模型(并且MediaFiles为集合)",
                        anyOf = {R.class, MediaFiles.class})
                )
            )
        }
    )
    @GetMapping("/files")
    public R<List<MediaFiles>> getFiles() {

        List<MediaFiles> files = mediaFilesService.getFiles();

        return R.success(files);
    }

    /**
     * 直接上传文件 不涉及分块
     *
     * @param file
     * @return
     * @throws Exception
     */
    @Operation(
        summary = "上传多个文件全部文件",
        description = "上传多个文件，并返回响应结果信息",
        parameters = @Parameter(name = "file", description = "文件名称"),
        deprecated = false,
        responses = {
            @ApiResponse(
                responseCode = "200",
                description = "响应成功",
                content = @Content(
                    mediaType = MediaType.MULTIPART_FORM_DATA_VALUE,
                    schema = @Schema(
                        title = "R和List<MediaFiles>组合模型",
                        description = "返回实体，AjaxResult内data为" +
                            "MediaFiles模型(并且MediaFiles为集合)",
                        anyOf = {R.class, MediaFiles.class})
                )
            )
        }
    )
    @PostMapping("/upload/files")
    // @RequestPart("file") 注解表示将 HTTP 请求中的一个文件作为请求参数传递给方法，并绑定到对应的方法参数上。
    public R<MediaFiles> uploadFile(@RequestPart("file") MultipartFile file) throws Exception {
        // 1.映射dto
        UploadFileParamsDto uploadFileParamsDto = new UploadFileParamsDto();
        // 文件名称
        uploadFileParamsDto.setFilename(file.getOriginalFilename());
        // 文件大小
        uploadFileParamsDto.setFileSize(file.getSize());
        // 文件类型
        uploadFileParamsDto.setFileType("图片");

        // 2.创建一个临时文件 以获取文件路径
        File tempFile = File.createTempFile("minio", "temp");
        file.transferTo(tempFile);
        // 取出文件的绝对路径
        String absolutePath = tempFile.getAbsolutePath();

        // 3.调用service
        MediaFiles mediaFiles = mediaFilesService.uploadFile(uploadFileParamsDto, absolutePath);

        return R.success(mediaFiles);
    }


    /**
     * 上传分块
     *
     * @param fileMd5    原始文件的md5
     * @param chunk      分块文件
     * @param chunkIndex 分块序号
     * @return
     * @throws Exception
     */
    @Operation(
        summary = "上传分块文件",
        description = "上传分块文件，并返回响应结果信息",
        parameters = {@Parameter(name = "md5", description = "md5值", required = true, example = ""),
            @Parameter(name = "chunk", description = "数据块", required = true, example = ""),
            @Parameter(name = "chunkIndex", description = "数据块索引", required = true, example = "")
        },
        deprecated = false,
        responses = {
            @ApiResponse(
                responseCode = "200",
                description = "响应成功",
                content = @Content(
                    mediaType = MediaType.APPLICATION_JSON_VALUE,
                    schema = @Schema(
                        title = "R和List<MediaFiles>组合模型",
                        description = "返回实体，AjaxResult内data为" +
                            "MediaFiles模型(并且MediaFiles为集合)",
                        anyOf = {R.class, MediaFiles.class})
                )
            )
        }
    )
    @PostMapping("/upload/uploadchunk")
    public R<Boolean> uploadChunk(@RequestParam("fileMd5") String fileMd5, @RequestParam("chunk") MultipartFile chunk,
                                  @RequestParam("chunkIndex") int chunkIndex) throws Exception {
        // 1.创建临时文件获取文件路径
        File tempFile = File.createTempFile("minio", "temp");
        chunk.transferTo(tempFile);
        // 取出文件的绝对路径
        String localFilePath = tempFile.getAbsolutePath();


        // 3.调用service上传分块
        Boolean result = mediaFilesService.uploadChunk(fileMd5, chunkIndex, localFilePath);
        return R.success(result);
    }

    /**
     * 检查分块
     *
     * @param fileMd5    原始文件的md5
     * @param chunkIndex 分块序号
     */
    @Operation(
        method = "POST",
        summary = "上传分块文件",
        description = "上传分块文件，并返回响应结果信息",
        parameters = {@Parameter(name = "fileMd5", description = "文件md5值", required = true, example = ""),
            @Parameter(name = "chunkIndex", description = "数据块索引", required = true, example = "")
        },
        deprecated = false,
        responses = {
            @ApiResponse(
                responseCode = "200",
                description = "响应成功",
                content = @Content(
                    mediaType = MediaType.APPLICATION_JSON_VALUE,
                    schema = @Schema(
                        title = "R和Boolean组合模型",
                        description = "返回实体，AjaxResult内data为Boolean",
                        anyOf = {R.class, Boolean.class})
                )
            )
        }
    )
    @PostMapping("/upload/checkchunk")
    public R<Boolean> checkChunk(@RequestParam("fileMd5") String fileMd5, @RequestParam("chunkIndex") int chunkIndex) {
        Boolean result = mediaFilesService.checkChunk(fileMd5, chunkIndex);
        return R.success(result);
    }

    /**
     * 合并文件
     *
     * @param fileMd5    原始文件的md5
     * @param fileName   原始文件的名称
     * @param chunkTotal 分块总数
     */
    @Operation(
        method = "POST",
        summary = "合并分块文件",
        description = "合并分块文件，并返回响应结果信息",
        parameters = {
            @Parameter(name = "fileMd5", description = "文件md5值", required = true, example = ""),
            @Parameter(name = "fileName", description = "文件名称", required = true, example = ""),
            @Parameter(name = "chunkTotal", description = "数据块总数", required = true, example = "")
        },
        deprecated = false,
        responses = {
            @ApiResponse(
                responseCode = "200",
                description = "响应成功",
                content = @Content(
                    mediaType = MediaType.APPLICATION_JSON_VALUE,
                    schema = @Schema(
                        title = "R和Boolean组合模型",
                        description = "返回实体，AjaxResult内data为Boolean",
                        anyOf = {R.class, Boolean.class})
                )
            )
        }
    )
    @PostMapping("/upload/mergechunks")
    public R<Boolean> mergeChunk(@RequestParam("fileMd5") String fileMd5, @RequestParam("fileName") String fileName, @RequestParam("chunkTotal") int chunkTotal) {
        // 1.映射文件参数信息
        UploadFileParamsDto uploadFileParamsDto = new UploadFileParamsDto();
        uploadFileParamsDto.setFilename(fileName);
        uploadFileParamsDto.setFileType("视频");

        Boolean res = mediaFilesService.mergeChunk(fileMd5, chunkTotal, uploadFileParamsDto);
        return R.success(res);
    }
}

